/* ComodifiableIterator.java
Purpose:
Description:
History:
Fri Dec 2 11:53:25 TST 2011, Created by tomyeh
Copyright (C) 2011 Potix Corporation. All Rights Reserved.
*/
package org.zkoss.util;
import java.util.Iterator;
import java.util.Collection;
import java.util.List;
import java.util.LinkedList;
/**
* A co-modifiable iterator. Used internally.
* @author tomyeh
*/
/*package*/ class ComodifiableIterator<F, T> implements Iterator<T> {
private final List<F> _visited = new LinkedList<F>();
private List<F> _lastVisited;
private final Collection<F> _col;
private Iterator<F> _it;
private F _next;
private Converter<F, T> _converter;
private boolean _nextAvail;
@SuppressWarnings("unchecked")
/*package*/ ComodifiableIterator(Collection<F> col, Converter<F, T> converter) {
_col = col;
_it = col.iterator();
_converter = converter != null ? converter: _identityConverter;
}
public boolean hasNext() {
//Note: we cannot just check hasNext() since it does not throw
//ConcurrentModificationException, so if _col is cleared, hasNext()
//might still return true! Moreover, hasNext() might return false
//while there is more
if (_nextAvail)
return true;
while (!_col.isEmpty()) { //isEmpty is reliable and empty is a common case
final F o;
try {
o = _it.next();
} catch (java.util.NoSuchElementException ex) {
return false;
} catch (java.util.ConcurrentModificationException ex) {
_lastVisited = new LinkedList<F>(_visited); //make a copy
_it = _col.iterator();
continue; //do it again
}
if (!removeFromLastVisited(o)) { //not visited before
_visited.add(o);
_next = o;
return _nextAvail = true;
}
}
return false;
}
public T next() {
if (_nextAvail) {
_nextAvail = false;
return _converter.convert(_next);
}
for (;;) {
final F o;
try {
o = _it.next();
} catch (java.util.ConcurrentModificationException ex) {
_lastVisited = new LinkedList<F>(_visited); //make a copy
_it = _col.iterator();
continue; //do it again
}
if (!removeFromLastVisited(o)) { //not visited before
_visited.add(o);
return _converter.convert(o);
}
}
}
private boolean removeFromLastVisited(F o) {
if (_lastVisited != null)
for (Iterator<F> it = _lastVisited.iterator(); it.hasNext();) {
if (it.next() == o) { //not equals (more restricted)
it.remove();
return true;
}
}
return false;
}
public void remove() {
_it.remove();
_nextAvail = false;
}
private static final Converter _identityConverter = new Converter() {
public Object convert(Object o) {
return o;
}
};
}